/** sps_auth_req.cpp - implemention of init auth code request
 */

#include "sps_config.h"

#define SJN_ID                       "id"
#define SJN_API_KEY                  "apiKey"
#define SJN_SECRET_KEY               "secretKey"
#define SJN_TEST_SECRET_KEY          "testSecretKey"
#define SJN_START_DATE               "startDate"
#define SJN_END_DATE                 "endDate"
#define SJN_USER_ID                  "userId"
#define SJN_STATE                    "state"
#define SJN_USE_MODE                 "useMode"
#define SJN_USE_SITUATION            "useSituation"
#define SJN_USE_PERMISSION           "usePermission"
#define SJN_USE_VERSION              "useVersion"

#define SJN_AGENT_CLIENT_MAC         "agentClientMac"


SpsAuthReq::SpsAuthReq(const std::string& ip, const std::string& mac)
  : SpsReq(ip, mac)
{
}

SpsAuthReq::~SpsAuthReq()
{
}

std::string SpsAuthReq::getResponse()
{
  if (err_ != ESPS_SUCCESS) {
    return SpsReq::getResponse();
  }
  
  json v;

  v[SJN_TYPE] = 1;
  v[SJN_CODE] = code_;
  v[SJN_RESULT_STATUS_CODE] = getResultStatusCode();
  v[SJN_RESULT_CODE] = getResultCode();
  v[SJN_RESULT_DESC] = getResultDesc();
  v[SJN_SESSION_ID] = session_;
  v[SJN_AGENT_CLIENT_IP] = local_ip_;
  v[SJN_ALGORITHM] = msgalgo_;

  json d;
  d[SJN_AGENT_CLIENT_MAC] = local_mac_;
  v[SJN_RESULT_DATA] = d;

  v[SJN_SIGNATURE] = generateVerify(v);
  
  return v.to_string();
}

/*******************************************************************************
 * Protected functions                                                         *
 ******************************************************************************/

int SpsAuthReq::load()
{
  int ret;

  ret = SpsReq::load();
  if (ret != ESPS_SUCCESS) {
    return ret;
  }

  try {
    json d = req_[SJN_SEND_DATA];
    id_ = d[SJN_ID].as_string();
    apikey_ = d[SJN_API_KEY].as_string();
    skey_ = d[SJN_SECRET_KEY].as_string();
    tskey_ = d[SJN_TEST_SECRET_KEY].as_string();
    usever_ = d[SJN_USE_VERSION].as_string();
    usemode_ = d[SJN_USE_MODE].as_int();
    usesitu_ = d[SJN_USE_SITUATION].as_int();
    useperm_ = d[SJN_USE_PERMISSION].as_int();
    state_ = d[SJN_STATE].as_int();
    userid_ = d[SJN_USER_ID].as_int();
    start_date_ = d[SJN_START_DATE].as_ulong();
    end_date_ = d[SJN_END_DATE].as_ulong();

    /* Save the private key. */
    updateAuthInfo();
    sps_priv_key = usemode_ ? skey_ : tskey_;
    SpsLog::instance().logDebug("PRIVATE KEY: %s", sps_priv_key.c_str());
    
  } catch (const json_exception& e) {
    SpsLog::instance().logError("load request from json failed (%s)", e.what());
    return ESPS_PARSE_FAILED;
  }
  
  return ESPS_SUCCESS;
}

int SpsAuthReq::verify()
{
  std::list<std::string> l;

  l.push_back(req_[SJN_TYPE].as_string());
  l.push_back(req_[SJN_CODE].as_string());
  l.push_back(req_[SJN_SESSION_ID].as_string());
  l.push_back(req_[SJN_AGENT_CLIENT_IP].as_string());
  l.push_back(req_[SJN_ALGORITHM].as_string());

  json d = req_[SJN_SEND_DATA];
  
  l.push_back(d[SJN_ID].as_string());
  l.push_back(d[SJN_API_KEY].as_string());
  l.push_back(d[SJN_SECRET_KEY].as_string());
  l.push_back(d[SJN_TEST_SECRET_KEY].as_string());
  l.push_back(d[SJN_START_DATE].as_string());
  l.push_back(d[SJN_END_DATE].as_string());
  l.push_back(d[SJN_USER_ID].as_string());
  l.push_back(d[SJN_STATE].as_string());
  l.push_back(d[SJN_USE_MODE].as_string());
  l.push_back(d[SJN_USE_SITUATION].as_string());
  l.push_back(d[SJN_USE_PERMISSION].as_string());
  l.push_back(d[SJN_USE_VERSION].as_string());

  l.push_back(sps_priv_key);

  l.sort();

  std::string msg;
  std::list<std::string>::const_iterator i;
  for (i = l.begin(); i != l.end(); i++) {
    msg += (*i + "&");
  }

  msg.erase(msg.end() - 1);
  
  return checkRequest(msg);
}

int SpsAuthReq::doit()
{
  return ESPS_SUCCESS;
}

std::string SpsAuthReq::generateVerify(const json& v)
{
  std::list<std::string> l;

  l.push_back(v[SJN_TYPE].as_string());
  l.push_back(v[SJN_CODE].as_string());
  l.push_back(v[SJN_RESULT_STATUS_CODE].as_string());
  l.push_back(v[SJN_RESULT_CODE].as_string());
  l.push_back(v[SJN_RESULT_DESC].as_string());
  l.push_back(v[SJN_SESSION_ID].as_string());
  l.push_back(v[SJN_AGENT_CLIENT_IP].as_string());
  l.push_back(v[SJN_ALGORITHM].as_string());

  json d = v[SJN_RESULT_DATA];
  l.push_back(d[SJN_AGENT_CLIENT_MAC].as_string());

  l.push_back(sps_priv_key);

  l.sort();

  std::string msg;
  std::list<std::string>::const_iterator i;
  for (i = l.begin(); i != l.end(); i++) {
    msg += (*i + "&");
  }

  msg.erase(msg.end() - 1);

  return getHash(msg);
}


int SpsAuthReq::updateAuthInfo()
{
  int       rc;
  sqlite3  *db;
  char      sql[1024];
  char     *msg;

  rc = sqlite3_open(sps_db_name.c_str(), &db);
  if (rc != SQLITE_OK) {
    SpsLog::instance().logError("open database failed(%s)", sqlite3_errmsg(db));
    goto ERR_EXIT;
    return -1;
  }

  /* TODO: Encrypt the secretKey and testSecretKey. */
  
  snprintf(sql, 1024,
	   "UPDATE AUTH_INFO SET init=1, id=%s, apiKey=%s," \
	   "useVersion=%s, useMode=%d, useSituation=%d," \
	   "usePermission=%d, userId=%d, state=%d, startDate=%d" \
	   "endDate=%d, secretKey=%s, testSecretKey=%s;",
	   id_.c_str(), apikey_.c_str(), usever_.c_str(), usemode_,
	   usesitu_, useperm_, userid_, state_, start_date_, end_date_,
	   skey_.c_str(), tskey_.c_str()
	   );

  rc = sqlite3_exec(db, sql, NULL, NULL, &msg);
  if (rc != SQLITE_OK) {
    SpsLog::instance().logError("update database failed(%s)", msg);
    sqlite3_free(msg);
    goto ERR_EXIT;
  }

 ERR_EXIT:

  sqlite3_close(db);
  
  return rc == SQLITE_OK ? 0 : -1;
}
